package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class DeviceServiceImpl implements DeviceService {

    // 客户端
    @Autowired
    private Client client;

    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 同步物联网平台产品列表 (同步到缓存中, 不走MySQL数据库, 所以不需要mapper层)
     * @return
     */
    @Override
    public void syncProductList() {

        // 请求参数
        QueryProductListRequest request = new QueryProductListRequest();
        request.setPageSize(100);
        request.setCurrentPage(1);
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        // 调用第三方查询产品列表
        QueryProductListResponse response;
        try {
            response = client.queryProductList(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR); // 物联网接口 - 查询产品，调用失败
        }

        // 判断，如果数据为空，则中断请求
        if (!response.getBody().success){
            throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR); // 物联网接口 - 查看所有产品列表，调用失败
        }

        // 获取数据，存储到redis
        List<ProductVo> productVoList = response.getBody().getData()
                .getList().getProductInfo().stream()
                .map(p -> BeanUtil.toBean(p, ProductVo.class)).collect(Collectors.toList());

        // 存储到redis
        redisTemplate.opsForValue().set(CacheConstants.ALL_PRODUCT_KEY, JSONUtil.toJsonStr(productVoList));
    }

    /**
     * 查询所有产品列表
     * @return
     */
    @Override
    public List<ProductVo> allProduct() {
        // 从缓存中获取数据
        String jsonStr = redisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCT_KEY);
        // 如果为空，返回空集合
        if (StrUtil.isEmpty(jsonStr)){
            return Collections.emptyList();
        }
        // 转换数据，并返回
        return JSONUtil.toList(jsonStr, ProductVo.class);
    }

    @Autowired
    private DeviceMapper deviceMapper;
    /**
     * 注册设备
     * @param deviceDto
     * @return
     */
    @Override
    public void registerDevice(DeviceDto deviceDto) {
        // 查询名字是否重复
        // 根据设备名称查询设备的数量, 数量大于0, 说明设么名字重复, 抛出异常结束
        Long count = deviceMapper.countByDeviceName(deviceDto.getDeviceName());
        if (count > 0){
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST); // 设备名称已存在，请重新输入
        }

        // 调出IOT的RegisterDevice接口注册设备
        RegisterDeviceRequest registerDeviceRequest = deviceDto.getRegisterDeviceRequest();
        // 设置设备实例id
        registerDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        RegisterDeviceResponse registerDeviceResponse = null;
        try {
            // 调出IOT的RegisterDevice接口注册设备
            registerDeviceResponse = client.registerDevice(registerDeviceRequest);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR); // 物联网接口 - 注册设备，调用失败
        }
        // 判断注册是否成功
        if (registerDeviceResponse == null || !registerDeviceResponse.getBody().success){
            // 注册不成功, 抛出异常
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR); // 物联网接口 - 注册设备，调用失败
        }

        // 将deviceDto转换成Device
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        // 获取iot生成的设备id
        device.setIotId(registerDeviceResponse.getBody().getData().getIotId());

        // 调用IOT的QueryProduct接口查询产品名字
        QueryProductRequest queryProductRequest = new QueryProductRequest();
        queryProductRequest.setProductKey(device.getProductKey());
        queryProductRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryProductResponse queryProductResponse = null;
        try {
            queryProductResponse = client.queryProduct(queryProductRequest);
        } catch (Exception e) {
            // 有异常不需要抛出, 这一步只是完成查询产品名字的动作, 查询是否成功下面会判断处理
            e.printStackTrace();
        }
        // 判断查询是否成功, 成功才可以设置产品名字
        if (queryProductResponse != null && queryProductResponse.getBody().success){
            // 查询成功, 设置产品名字
            device.setProductName(queryProductResponse.getBody().getData().getProductName());
        }

        // 判断设备类型locationType是否为0, 如果为0设置物理位置的类型为-1
        if (device.getLocationType() == 0){
            device.setPhysicalLocationType(-1);
        }

        // 调用数据库保存设备
        // 设置是否包含门禁为0
        device.setHaveEntranceGuard(0);
        try {
            // 调用数据库保存设备
            deviceMapper.insertSelective(device);
        } catch (Exception e) {
            // 保存发生异常, 调用IOT的DeleteDevice删除对应设备

            // 删除iot中的设备数据
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setDeviceName(device.getDeviceName());
            deleteDeviceRequest.setIotId(device.getIotId());
            deleteDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            deleteDeviceRequest.setProductKey(device.getProductKey());
            try {
                // 用IOT的DeleteDevice删除对应设备
                client.deleteDevice(deleteDeviceRequest);
            } catch (Exception ex) {
                // 删除设备失败, 抛出异常
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR); // 物联网接口 - 删除设备，调用失败
            }

            // 保存失败, 抛出异常
            throw new BaseException(BasicEnum.RE_SELECT_PRODUCT); // 该老人/位置已绑定该产品，请重新选择
        }
    }

    /**
     * 分页查询设备列表
     * @param devicePageQueryDto
     * @return
     */
    @Override
    public PageResponse<DeviceVo> pageQueryDevice(DevicePageQueryDto devicePageQueryDto) {
        PageHelper.startPage(devicePageQueryDto.getPageNum(), devicePageQueryDto.getPageSize());
        Page<DeviceVo> page  = deviceMapper.selectByPage(devicePageQueryDto);
        return PageResponse.of(page, DeviceVo.class);
    }

    /**
     * 查询设备详细数据
     * @param request 查询设备详情请求模型
     * @return 设备详细数据
     */
    @Override
    public DeviceVo queryDeviceDetail(QueryDeviceDetailRequest request) {
        // 调用IOT的查询设备详情接口获取数据
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId()); // 这个参数如果有就必须要传
        QueryDeviceDetailResponse response = null;
        try {
             response = client.queryDeviceDetail(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR); // 物联网接口 - 查询产品，调用失败
        }
        // 判断接口是否调通, 没调通就抛异常
        if (response == null || !response.getBody().success){
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR); // 物联网接口 - 查询产品，调用失败
        }
        // 调通就获取设备数据
        QueryDeviceDetailResponseBody.QueryDeviceDetailResponseBodyData data = response.getBody().getData();

        // 查询数据库的数据
        DeviceVo deviceVo = deviceMapper.selectByIotId(response.getBody().getData().getIotId());

        // 合并两个数据
        // CopyOptions.create().ignoreNullValue() 将data对象中非空属性值赋值给deviceVo
        BeanUtil.copyProperties(data, deviceVo, CopyOptions.create().ignoreNullValue());

        // 返回数据
        return deviceVo;
    }

    /**
     * 查询指定设备的物模型运行状态
     * @param request
     * @return
     */
    @Override
    public Object QueryDevicePropertyStatus(QueryDevicePropertyStatusRequest request) {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDevicePropertyStatusResponse response = null;
        try {
            response = client.queryDevicePropertyStatus(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR); // 物联网接口 - 查询设备的物模型运行状态，调用失败
        }
        return response.getBody().getData();
    }

    /**
     * 查看指定产品的已发布物模型中的功能定义详情
     * @param request
     * @return
     */
    @Override
    public Object QueryThingModelPublished(QueryThingModelPublishedRequest request) {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryThingModelPublishedResponse response = null;
        try {
            response = client.queryThingModelPublished(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR); // 物联网接口 - 查询物模型数据，调用失败
        }
        return response.getBody().getData();
    }

    /**
     * 修改设备备注名称
     * @param deviceDto
     * @return
     */
    @Override
    public void UpdateDevice(DeviceDto deviceDto) {
        // 修改IOT数据 阿里云对应接口方法：client.batchUpdateDeviceNickname(request)
        BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        List<BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo> deviceNicknameInfo = new ArrayList<>();
        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo batchUpdateDeviceNicknameRequestDeviceNicknameInfo = new BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo();
        batchUpdateDeviceNicknameRequestDeviceNicknameInfo.setDeviceName(deviceDto.getDeviceName());
        batchUpdateDeviceNicknameRequestDeviceNicknameInfo.setNickname(deviceDto.getNickname());
        batchUpdateDeviceNicknameRequestDeviceNicknameInfo.setProductKey(deviceDto.getProductKey());
        deviceNicknameInfo.add(batchUpdateDeviceNicknameRequestDeviceNicknameInfo);
        request.setDeviceNicknameInfo(deviceNicknameInfo);
        BatchUpdateDeviceNicknameResponse response = null;
        try {
            response = client.batchUpdateDeviceNickname(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR); // 物联网接口 - 批量修改设备名称，调用失败
        }

        // 判断
        if (response == null || !response.getBody().success){
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR); // 物联网接口 - 批量修改设备名称，调用失败
        }

        deviceMapper.updateByPrimaryKeySelective(BeanUtil.toBean(deviceDto, Device.class));
    }

    /**
     * 删除设备
     * @param deviceDto
     * @return
     */
    @Override
    public void DeleteDevice(DeviceDto deviceDto) {
        // 删除IOT设备
        DeleteDeviceRequest request = new DeleteDeviceRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        request.setIotId(deviceDto.getIotId());
        request.setProductKey(deviceDto.getProductKey());
        request.setDeviceName(deviceDto.getDeviceName());
        try {
            client.deleteDevice(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR); // 物联网接口 - 删除设备，调用失败
        }
        deviceMapper.deleteByIotId(deviceDto.getIotId());
    }
}
